package com.zyndev.sanchi.util;

import com.zyndev.sanchi.domain.Mapping;
import com.zyndev.sanchi.domain.Param;
import org.springframework.web.bind.annotation.*;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * The type Mapping util.
 */
public class MappingUtil {

    private static final String requestMathod[] = {"GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "TRACE"};

    /**
     * Gets paths.
     * 得到类上的路由
     *
     * @param clazz the clazz
     * @return the paths
     */
    public static List<String> getPaths(Class clazz) {
        // 判断类上面时候有 requestMapping
        RequestMapping requestMapping = (RequestMapping) clazz.getAnnotation(RequestMapping.class);
        List<String> paths = new ArrayList<>();
        if (requestMapping != null) {
            String[] value = requestMapping.value();
            if (value != null && value.length > 0) {
                paths = new ArrayList<>(value.length);
                for (String e : value) {
                    if (e.startsWith("/")) {
                        paths.add(e);
                    } else {
                        paths.add("/" + e);
                    }
                }
            }
        }
        if (paths.isEmpty()) {
            paths.add("");
        }
        return paths;
    }

    public static List<Mapping> getMappings(Class controller, Map<String, ClassCommentInfo> classCommentInfoMap) {

        List<String> paths = getPaths(controller);

        Method[] methods = controller.getDeclaredMethods();
        List<Mapping> mappingList = new ArrayList<>();
        for (Method method : methods) {

            String[] allowMethods = null;
            String[] url = null;
            RequestMethod[] requestMethods = null;

            RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
            GetMapping getMapping = method.getAnnotation(GetMapping.class);
            PostMapping postMapping = method.getAnnotation(PostMapping.class);
            DeleteMapping deleteMapping = method.getAnnotation(DeleteMapping.class);

            if (requestMapping != null) {
                url = requestMapping.value();
                if (requestMethods == null || requestMethods.length == 0) {
                    allowMethods = requestMathod;
                } else {
                    allowMethods = new String[requestMethods.length];
                    for (int i = 0; i < requestMethods.length; ++i) {
                        if (requestMethods[i] == RequestMethod.GET) {
                            allowMethods[i] = "GET";
                        } else if (requestMethods[i] == RequestMethod.HEAD) {
                            allowMethods[i] = "HEAD";
                        } else if (requestMethods[i] == RequestMethod.POST) {
                            allowMethods[i] = "POST";
                        } else if (requestMethods[i] == RequestMethod.PUT) {
                            allowMethods[i] = "PUT";
                        } else if (requestMethods[i] == RequestMethod.PATCH) {
                            allowMethods[i] = "PATCH";
                        } else if (requestMethods[i] == RequestMethod.DELETE) {
                            allowMethods[i] = "DELETE";
                        } else if (requestMethods[i] == RequestMethod.OPTIONS) {
                            allowMethods[i] = "OPTIONS";
                        } else {
                            allowMethods[i] = "TRACE";
                        }
                    }
                }
            } else if (getMapping != null) {
                url = getMapping.value();
                allowMethods = new String[]{"GET"};
            } else if (postMapping != null) {
                url = postMapping.value();
                allowMethods = new String[]{"POST"};
            } else if (deleteMapping != null) {
                url = deleteMapping.value();
                allowMethods = new String[]{"DELETE"};
            } else {
                continue;
            }


            Map<String, MethodParamInfo> methodParamInfoMap
                    = classCommentInfoMap.get(method.getName()).getMethodParamInfoMap();

            Parameter[] parameters = method.getParameters();
            List<Param> paramList = new ArrayList<>(parameters.length);
            for (Parameter parameter : parameters) {
                RequestParam requestParam = parameter.getAnnotation(RequestParam.class);
                if (requestParam != null) {
                    MethodParamInfo methodParamInfo = null;
                    if (methodParamInfoMap != null) {
                        methodParamInfo = methodParamInfoMap.get(requestParam.value());
                    }
                    Param param = new Param();
                    if (methodParamInfo != null) {
                        param.setRemark(methodParamInfo.getComment());
                    }
                    param.setName(requestParam.value());
                    param.setType(parameter.getType().getName());
                    paramList.add(param);
                }
            }

            for (String path : paths) {
                for (String url1 : url) {
                    Mapping mapping = new Mapping();
                    if (url1.startsWith("/")) {
                        mapping.setUrl(paths.get(0) + url1);
                    } else {
                        mapping.setUrl(paths.get(0) + "/" + url1);
                    }
                    mapping.setMethod(allowMethods);
                    mapping.setParamList(paramList);
                    mappingList.add(mapping);
                }
            }
        }
        return mappingList;
    }

}
